package com.zmn.uac.business.impl.oauth.login;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.saas.common.dro.app.AppInfoDRO;
import com.zmn.uac.business.interfaces.channel.ChannelBService;
import com.zmn.uac.business.interfaces.oauth.login.MobileLoginBService;
import com.zmn.uac.business.interfaces.user.UserInfoBService;
import com.zmn.uac.client.PassLoginClient;
import com.zmn.uac.client.UserListClient;
import com.zmn.uac.client.UserRegisterClient;
import com.zmn.uac.common.dio.oauth.login.TempCodeDIO;
import com.zmn.uac.common.dio.oauth.login.UserAuthLoginDIO;
import com.zmn.uac.common.dro.oauth.login.UserAuthLoginDRO;
import com.zmn.uac.common.entity.oauth.login.UniInfo;
import com.zmn.uac.common.info.UserAuthPhoneInfo;
import com.zmn.uac.common.info.mobile.MobileUserAuthInfo;
import com.zmn.uac.util.HttpClientsUtil;
import com.zmn.uac.util.LogAlibabaUtil;
import com.zmn.uuc.common.constant.PassConsts;
import com.zmn.uuc.common.dio.pass.UserMobileLoginDIO;
import com.zmn.uuc.common.dio.user.UserRegisterByMobileNoCaptchaDIO;
import com.zmn.uuc.common.dro.user.UserBaseDRO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.List;
import java.util.Objects;
import java.util.TreeMap;
import java.util.stream.Collectors;

/**
 * 类描述：手机号登录业务
 *
 * @author xujie
 * @since 2021/06/14 16:43
 */
@Slf4j
@Service
public class MobileLoginBServiceImpl implements MobileLoginBService {

    private static final String TAG = "手机号登录业务实现";

    public static final String VIRTUAL_URL = "https://cd0d9285-fd01-46b7-a3bb-6f8545eb0b11.bspapp.com/http/getMobile";

    @Resource
    UserInfoBService userInfoBusinessService;

    @Resource
    ChannelBService channelBusinessService;

    @Resource
    UserRegisterClient userRegisterClient;

    @Resource
    UserListClient userListClient;

    @Resource
    PassLoginClient passLoginClient;

    @Override
    public ResponseDTO<UserAuthLoginDRO> login(UserAuthLoginDIO dio, UserAuthPhoneInfo authPhoneInfo) {

        MobileUserAuthInfo authInfo = (MobileUserAuthInfo) authPhoneInfo;
        Integer channelId = dio.getChannelId();
        AppInfoDRO app = channelBusinessService.getShowAppByChannelIdOrShopId(channelId, dio.getShopId());
        if (Objects.isNull(app)) {
            log.error("[{}], 根据channelId：{}，查询三方应用信息为null", TAG, channelId);
        }
        ResponseDTO<String> result = null;
        if (Objects.nonNull(app)) {
            UniInfo uniInfo = JSONObject.parseObject(app.getCustomFieldValue(), UniInfo.class);
            if (Objects.isNull(uniInfo)) {
                log.info("[{}]，应用扩展字段转换异常，customFieldValue:{}，channelId:{}", TAG, app.getCustomFieldValue(), channelId);
            } else {
                TreeMap<String, String> treeMap = new TreeMap<>();
                String secret = uniInfo.getUniApiSecret();
                treeMap.put("access_token", authInfo.getAccessToken());
                treeMap.put("openid", authInfo.getOpenid());
                treeMap.put("appid", uniInfo.getUniAppId());
                treeMap.put("apiKey", uniInfo.getUniApiKey());
                treeMap.put("apiSecret", secret);
                String dataUrl = treeMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
                String sign = sha256Hmac(dataUrl, secret);
                treeMap.put("sign", sign);
                result = getMobile(treeMap, uniInfo.getUniVirtualUrl());
            }
        }
        if (Objects.isNull(result) || !result.isSuccess()) {
            String secret = "f4c4fb574721bbc84badb233d3066eb1";
            TreeMap<String, String> treeMap = new TreeMap<>();
            treeMap.put("access_token", authInfo.getAccessToken());
            treeMap.put("openid", authInfo.getOpenid());
            String dataUrl = treeMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
            String sign = sha256Hmac(dataUrl, secret);
            treeMap.put("sign", sign);
            result = getMobile(treeMap, VIRTUAL_URL);
        }
        if (!result.isSuccess()) {
            return ResponseDTO.fail(result.getMessage());
        }
        String phoneNumber = result.getData();
        List<UserBaseDRO> userBaseList = userListClient.listUserByMobile(phoneNumber, Boolean.TRUE);
        // 如果是新用户就注册
        Boolean newUser = CollectionUtil.isNullOrEmpty(userBaseList);

        if (newUser) {
            UserRegisterByMobileNoCaptchaDIO noCaptcha = new UserRegisterByMobileNoCaptchaDIO();
            noCaptcha.setIp(dio.getIp());
            noCaptcha.setMobile(phoneNumber);
            noCaptcha.setChannelId(channelId);
            noCaptcha.setChannelName(channelBusinessService.getNameByChannelId(channelId));
            noCaptcha.setPlat(dio.getPlat());
            noCaptcha.setEntrance(dio.getEntrance());

            userRegisterClient.registerByMobileNoCaptcha(noCaptcha);
        }
        UserMobileLoginDIO mobileLogin = new UserMobileLoginDIO();
        mobileLogin.setChannelId(dio.getChannelId());
        mobileLogin.setChannelName(channelBusinessService.getNameByChannelId(channelId));
        mobileLogin.setPlat(dio.getPlat());
        mobileLogin.setIdentityType(PassConsts.PASS_IDENTITY_TYPE_PERSON);
        mobileLogin.setMobile(phoneNumber);
        String token = passLoginClient.loginThirdByMobile(mobileLogin);
        ResponseDTO<UserAuthLoginDRO> authLoginResponse = userInfoBusinessService.getUserInfoByToken(token);
        if (authLoginResponse.isSuccess()) {
            authLoginResponse.getData().setNewUser(newUser);
            UserAuthLoginDRO userAuthLoginDRO = authLoginResponse.getData();
            LogAlibabaUtil.mobileLoginLog(userAuthLoginDRO, authPhoneInfo, mobileLogin, authInfo);
        }
        return authLoginResponse;
    }

    @Override
    public ResponseDTO<String> getOpenIdByCode(TempCodeDIO tempCodeDIO) {
        return null;
    }

    private ResponseDTO<String> getMobile(TreeMap<String, String> treeMap, String url) {

        String jsonResult = HttpClientsUtil.executeGet(url + HttpClientsUtil.splicingUrlData(treeMap));
        if (jsonResult == null) {
            return ResponseDTO.fail("获取手机号异常");
        }
        log.info("[{}], treeMap:{}, 换手机号, 返回信息：{}", TAG, JSONObject.toJSONString(treeMap), jsonResult);
        JSONObject jsonObject = JSON.parseObject(jsonResult);
        String phoneNumberStr = "phoneNumber";
        if (!jsonObject.containsKey(phoneNumberStr) || !StringUtil.isMobile(jsonObject.getString(phoneNumberStr))) {
            return ResponseDTO.fail("获取手机号失败");
        }
        String phoneNumber = jsonObject.getString(phoneNumberStr);
        return ResponseDTO.success(phoneNumber);
    }

    /**
     * 将加密后的字节数组转换成字符串
     *
     * @param b 字节数组
     * @return 字符串
     */
    private static String byteArrayToHexString(byte[] b) {

        StringBuilder hs = new StringBuilder();
        String stmp;
        for (int n = 0; b != null && n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0XFF);
            if (stmp.length() == 1) {
                hs.append('0');
            }
            hs.append(stmp);
        }
        return hs.toString().toLowerCase();
    }


    /**
     * sha256_HMAC加密
     *
     * @param message 消息
     * @param secret  秘钥
     * @return 加密后字符串
     */
    private static String sha256Hmac(String message, String secret) {
        String hash = GlobalConsts.SPLITER_EMPTY;
        try {
            Mac sha256Hmac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
            sha256Hmac.init(secretKey);
            byte[] bytes = sha256Hmac.doFinal(message.getBytes());
            hash = byteArrayToHexString(bytes);
        } catch (Exception e) {
            log.error("[{}], sha256_HMAC加密异常：{}", TAG, e.getMessage(), e);
        }
        return hash;
    }

    public static void main(String[] args) {

        String token = "U1RzaWQwMDAwMDAxNjI0MDA5ODQ0MDcxS1NPdWd1Z3V5Z3BtaTd3d3ZRb2Z6TGJwZVpKYXd3eEl8fDF8djJ8MQ==";
        String openid = "12092957B632A08F176C99900957B21AA33152f8f13ac784c0eba581cc5a146f25e65";
        String secret = "f4c4fb574721bbc84badb233d3066eb1";
        TreeMap<String, String> treeMap = new TreeMap<>();
        treeMap.put("access_token", token);
        treeMap.put("openid", openid);
        String dataUrl = treeMap.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).collect(Collectors.joining("&"));
        String sign = sha256Hmac(dataUrl, secret);
        treeMap.put("sign", sign);
        System.out.println(VIRTUAL_URL + HttpClientsUtil.splicingUrlData(treeMap));
        String jsonResult = HttpClientsUtil.executeGet(VIRTUAL_URL + HttpClientsUtil.splicingUrlData(treeMap));
        System.out.println(jsonResult);
    }
}
